package com.mars.designpatterns.singleton;


import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class SingletonTest {
    public static void main(String[] args) throws Exception {
// 方法1：单线程获取单例对象
//        LazySingleton lazySingleton = LazySingleton.getInstance();

// 方法2：多线程获取懒汉式单例对象
//        Thread t1 = new Thread(new ThreadTest());
//        Thread t2 = new Thread(new ThreadTest());
//        t1.start();
//        t2.start();

// 方法3：静态内部类获取单例对象
//        StaticInnerClassSingleton staticInnerClassSingleton = StaticInnerClassSingleton.getInstance();
//        System.out.println("program end");

// 方法4：破坏单例模式
//        HungrySingleton instance = HungrySingleton.getInstance();
//        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("singletonFile"));
//        oos.writeObject(instance);
//        File file = new File("singletonFile");
//        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
//
//        HungrySingleton newInstance = (HungrySingleton)ois.readObject();
//
//        System.out.println(instance);
//        System.out.println(newInstance);
//        System.out.println(instance == newInstance);

//  方法5 反射攻击解决方法：饿汉模式，在类加载是初始化，反射攻击解决
//        Class objectClass = HungrySingleton.class;
//        Constructor con = objectClass.getDeclaredConstructor();
        // 放开私有构造器的权限,在类加载的时候，在构造方法做反射防御的操作
        //con.setAccessible(true);
        // 通过单例方法的获取到的对象
        //HungrySingleton instance1 = HungrySingleton.getInstance();
        // 通过反射的方式获取HungrySingleton对象
        //HungrySingleton instance2 = (HungrySingleton)con.newInstance();
        //System.out.println(instance1);
        //System.out.println(instance2);
        //System.out.println(instance1 == instance2);

//  方法6 反射攻击解决方法：懒汉模式，反射攻击解决
//        Class objectClass = LazySingleton.class;
//        Constructor con = objectClass.getDeclaredConstructor();
//        // 放开私有构造器的权限,在类加载的时候，在构造方法做反射防御的操作
//        con.setAccessible(true);
//        // 通过单例方法的获取到的对象
//        LazySingleton instance1 = LazySingleton.getInstance();
//        // 通过反射的方式获取HungrySingleton对象
//        LazySingleton instance2 = (LazySingleton)con.newInstance();
//        System.out.println(instance1);
//        System.out.println(instance2);
//        System.out.println(instance1 == instance2);
// 方法7 枚举类单例
        // 以下为序列化反序列化操作
        //EnumsInstance instance = EnumsInstance.getInstance();
        //instance.setData(new Object());
        //ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("singletonFile"));
        //oos.writeObject(instance);
        //File file = new File("singletonFile");
        //ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
        //
        //EnumsInstance newInstance = (EnumsInstance)ois.readObject();
        //
        //// 测试枚举持有的INSTANCE
        //System.out.println(instance);
        //System.out.println(newInstance);
        //System.out.println(instance == newInstance);
        //// 测试枚举中持有的data属性
        //System.out.println(instance.getData());
        //System.out.println(newInstance.getData());
        //System.out.println(instance.getData() == newInstance.getData());
// 方法8：容器单例
        Thread t1 = new Thread(new ThreadTest());
        Thread t2 = new Thread(new ThreadTest());
        t1.start();
        t2.start();
        // 反射的操作,会报错
        Class objectClass = EnumsInstance.class;
        Constructor con = objectClass.getDeclaredConstructor(String.class,int.class);
        // 放开私有构造器的权限,在类加载的时候，在构造方法做反射防御的操作
        con.setAccessible(true);
        // 通过单例方法的获取到的对象
        EnumsInstance instance1 = EnumsInstance.getInstance();
        // 通过反射的方式获取HungrySingleton对象
        EnumsInstance instance2 = (EnumsInstance)con.newInstance("mars",1);
        System.out.println(instance1);
        System.out.println(instance2);
        System.out.println(instance1 == instance2);
    }
}
